package com.ding.easycontroller.work;

import com.ding.easycontroller.helper.EcSession;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.Data;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
    提供websocket的相关操作

    使用方法几乎和Controller相同

 */
@Data
public class WebSocket extends Script {


    {
        setType("websocket");
    }

    //判断是否具有处理消息的接口
    private static Pattern _handle_message_pattern = Pattern.compile("function[ \t\n]+_onMessage[ \t\n]*\\(([ \t\n]*)\\)");
    private static Pattern _open_pattern = Pattern.compile("function[ \t\n]+_onOpen[ \t\n]*\\(([ \t\n]*)\\)");
    private static Pattern _close_pattern = Pattern.compile("function[ \t\n]+_onClose[ \t\n]*\\(([ \t\n]*)\\)");

    //接口地址
    private String uri;

    //执行引擎
    private ScriptEngine scriptEngine;

    //处理消息的方法名称
    private String localMessageFunctionName, localOpenFunctionName, localCloseFunctionName;

    //ant风格路径
    private String regex;

    //带有路径的正则
    private String regexWithPathParams;

    //路径参数名称
    private List<String> pathParams;

    //用于提取路径占位符的正则
    private Pattern pathParamsPattern;

    //模糊比率
    private double rate = 0;

    //用于初始化的js代码
    private String initJs;

    //初始化
    protected void doInit() {

        if (initJs == null) {
            preInit();
        }
        try {
            scriptEngine.eval(initJs);
        } catch (ScriptException e) {
            throw new RuntimeException(e);
        }

    }

    public void doDestroy() {
        try {
            scriptEngine.eval("delete " + localMessageFunctionName);
            scriptEngine.eval("delete " + localOpenFunctionName);
            scriptEngine.eval("delete " + localCloseFunctionName);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void preInit() {

        if (js == null) {
            js = "";
        }


        if (_handle_message_pattern.matcher(js).find()) {
            localMessageFunctionName = "__websocket_message_" + id;
            initJs = "function " + localMessageFunctionName + "(_heads,_pathValues,_session,_msg)" + "{\n" + js + "\n_onMessage();}\n";
        }


        if (_open_pattern.matcher(js).find()) {
            localOpenFunctionName = "__websocket_open_" + id;
            initJs += "function " + localOpenFunctionName + "(_heads,_pathValues,_session)" + "{\n" + js + "\n_onOpen();}\n";
        }

        if (_close_pattern.matcher(js).find()) {
            localCloseFunctionName = "__websocket_close_" + id;
            initJs += "function " + localCloseFunctionName + "(_heads,_pathValues,_session,_status)" + "{\n" + js + "\n_onClose();}\n";
        }

        // System.out.println(initJs);


        //生成路径正则
        if (pathParams != null) {

            //编译路径参数
            pathParamsPattern = Pattern.compile(regexWithPathParams);
        }

    }


    //准备参数
    private Object[] prepare(WebSocketSession session) {

        try {
            URI uri = session.getUri();
            ScriptObjectMirror pathVariables = (ScriptObjectMirror) ((Invocable) scriptEngine).invokeFunction("__createJson");
            if (pathParamsPattern != null) {
                String requestURI = URLDecoder.decode(uri.getPath(), "UTF-8");
                Matcher matcher = pathParamsPattern.matcher(requestURI);
                if (matcher.find()) {
                    for (String pathParam : pathParams) {
                        pathVariables.put(pathParam, matcher.group(pathParam));
                    }
                }
            }
            ScriptObjectMirror reqHeads = (ScriptObjectMirror) ((Invocable) scriptEngine).invokeFunction("__createJson");
            HttpHeaders handshakeHeaders = session.getHandshakeHeaders();
            Object params[] = new Object[4];//第四个作为空位,处理消息时会用到
            params[0] = handshakeHeaders;
            params[1] = pathVariables;
            params[2] = new EcSession(session);
            return params;
        } catch (Exception ignore) {
            return null;
        }

    }


    //处理连接
    public void handleOpen(WebSocketSession session) {

        if (localOpenFunctionName == null) {
            return;
        }

        try {
            Object[] params = prepare(session);
            ((Invocable) scriptEngine).invokeFunction(localOpenFunctionName, (Object[]) params);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //处理消息
    public void handleMessage(WebSocketSession session, String msg) {

        if (localMessageFunctionName == null) {
            return;
        }

        try {
            Object[] params = prepare(session);
            params[3] = msg;
            ((Invocable) scriptEngine).invokeFunction(localMessageFunctionName, (Object[]) params);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //处理关闭
    public void handleClose(WebSocketSession session, CloseStatus closeStatus) {

        if (localCloseFunctionName == null) {
            return;
        }

        try {
            Object[] params = prepare(session);
            params[3] = closeStatus;
            ((Invocable) scriptEngine).invokeFunction(localCloseFunctionName, (Object[]) params);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public boolean equals(Object obj) {
        return super.equals(obj);
    }

}
